import { ref, reactive, computed, nextTick } from "vue";
import { ElMessageBox, ElMessage } from "element-plus";

export function useCrud(service, optionFunction = () => {}) {
  const data = ref([]);
  const context = reactive({
    selectionList: [],
    params: {},
    loading: false,
    form: {},
    searchForm: {},
    page: {},
    isTree: false
  });

  const crud = ref(null);

  const selectedIds = computed(() => {
    return context.selectionList.map(item => item.id);
  });

  const option = computed(() => {
    return optionFunction(context);
  });

  const bindVal = reactive({
    data,
    tableLoading: context.loading,
    // option: option.value,
    rowParentKey: "parent"
  });

  const getList = async () => {
    if (context.isTree && Object.keys(context.params).length === 0) {
      getRootNodes();
      return;
    }
    const listFunction = service.page || service.list;
    if (!listFunction) {
      return;
    }
    context.loading = true;
    try {
      const resData = await listFunction(context.page, {
        ...context.params,
        ...context.searchForm
      });
      if (resData.records) {
        data.value = resData.records;
        context.page.total = resData.total;
      } else {
        data.value = resData;
      }
      context.loading = false;
    } catch (e) {
      console.error(e);
      context.loading = false;
    }
  };

  const treeLoad = async (tree, treeNode, resolve) => {
    if (!service.treeLoad) {
      return;
    }
    try {
      const res = await service.treeLoad(tree.id);
      resolve(res.data.data);
    } catch (e) {
      console.error(e);
    }
  };

  const getRootNodes = async () => {
    context.loading = true;
    try {
      const res = await service.treeLoad();
      data.value = [];
      nextTick(() => {
        data.value = res.data.data;
      });
      context.loading = false;
    } catch (e) {
      console.error(e);
      context.loading = false;
    }
  };
  const rowSave = (row, done, loading) => {
    if (!service.submit) {
      return;
    }
    service
      .submit(context.form)
      .then(() => {
        ElMessage.success({
          message: "保存成功！"
        });
        getList();
        done();
      })
      .catch(() => {
        loading();
      });
  };
  const rowUpdate = async (row, index, done, loading) => {
    if (!service.submit) {
      return;
    }
    try {
      await service.submit(context.form);
      ElMessage.success({
        message: "修改成功！"
      });
      done();
      await getList();
    } catch (e) {
      console.error(e);
      loading();
    }
  };
  const rowDel = async row => {
    const deleteMethod = service.delete || service.remove;
    if (!deleteMethod) {
      return;
    }
    await deleteConfirm();
    await deleteMethod([row.id]);
    await getList();
  };
  const rowsDel = async () => {
    const deleteMethod = service.delete || service.remove;
    if (!deleteMethod) {
      return;
    }
    await checkSelection();
    await deleteConfirm();
    await deleteMethod(context.selectionList.map(row => row.id));
    await getList();
  };

  const deleteConfirm = () => {
    return ElMessageBox.confirm("确定要删除选中的记录?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    });
  };

  const doSearch = async (params, done) => {
    context.page.currentPage = 1;
    await getList();
    if (done) done();
  };

  const selectionChange = list => {
    context.selectionList = list;
  };

  const refreshChange = () => {
    getList();
  };

  const reload = () => {
    getList();
  };

  const searchReset = (params, done) => {
    doSearch(params, done);
  };

  const checkSelection = (multi = true) => {
    const length = context.selectionList.length;
    if (length === 0) {
      const msg = "请先选择要操作的数据";
      ElMessage.warning(msg);
      return Promise.reject(msg);
    }
    if (multi === false && length > 1) {
      const msg = "请先选择一条数据";
      ElMessage.warning(msg);
      return Promise.reject(msg);
    }
    return Promise.resolve();
  };

  const operateConfirm = msg => {
    return ElMessageBox.$confirm(msg || "确定要操作选中的记录?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    });
  };

  const events = {
    "on-load": getList,
    "tree-load": treeLoad,
    "row-save": rowSave,
    "row-update": rowUpdate,
    "row-del": rowDel,
    rowsDel,
    "selection-change": selectionChange,
    "refresh-change": refreshChange,
    "search-change": doSearch,
    "search-reset": searchReset
  };

  return {
    data,
    context,
    bindVal,
    events,
    crud,
    option,
    checkSelection,
    operateConfirm,
    reload,
    selectedIds
  };
}
